#pragma once

namespace AVUI {
class ContentControl;
class HeaderedContentControl;
class HeaderedItemsControl;
class Popup;

class ModelTreeEnumerator : public Object, public IEnumerator
{
public:

#pragma region Internal Methods

    DECLARE_ELEMENT(ModelTreeEnumerator, Object);
    ModelTreeEnumerator(Object* pContent) : m_index(-1), m_pContent(pContent) { }

#pragma endregion Internal Methods

protected:

#pragma region Protected Methods

    virtual bool MoveNext();
    virtual void Reset();
    void VerifyUnchanged();
    bool IsInvalid() AVUI_OVERRIDE { return false; }
    Object* get_Object() { return this; }

#pragma endregion Protected Methods

#pragma region Protected Properties

    Object* get_Content() { return m_pContent; }
    virtual TRefCountedPtr<Object> get_Current();
    int get_Index() { return m_index; }
    void set_Index(int value) { m_index = value; }
    virtual bool get_IsUnchanged() = 0;

#pragma endregion Protected Properties

private:

#pragma region Private Fields

    TRefCountedPtr<Object> m_pContent;
    int m_index;

#pragma endregion Private Fields

};

class ContentModelTreeEnumerator : public ModelTreeEnumerator
{
public:
    DECLARE_ELEMENT(ContentModelTreeEnumerator, ModelTreeEnumerator);
    ContentModelTreeEnumerator(ContentControl* pContentControl, Object* pContent) : ModelTreeEnumerator(pContent), m_pOwner(pContentControl) { }

protected:
    virtual bool get_IsUnchanged() AVUI_OVERRIDE;

private:
    TWeakPtr<ContentControl> m_pOwner;
};

class HeaderedContentModelTreeEnumerator : public ModelTreeEnumerator
{
public:
    DECLARE_ELEMENT(HeaderedContentModelTreeEnumerator, ModelTreeEnumerator);
    HeaderedContentModelTreeEnumerator(HeaderedContentControl* pHeaderedContentControl, Object* pContent, Object* pHeader) : ModelTreeEnumerator(pHeader), m_pOwner(pHeaderedContentControl), m_pContent(pContent) { }

protected:
    virtual bool MoveNext() AVUI_OVERRIDE;
    virtual TRefCountedPtr<Object> get_Current() AVUI_OVERRIDE;
    virtual bool get_IsUnchanged() AVUI_OVERRIDE;

private:
    TRefCountedPtr<Object> m_pContent;
    TWeakPtr<HeaderedContentControl> m_pOwner;
};

class HeaderedItemsModelTreeEnumerator : public ModelTreeEnumerator
{
public:
    DECLARE_ELEMENT(HeaderedContentModelTreeEnumerator, ModelTreeEnumerator);
    HeaderedItemsModelTreeEnumerator(HeaderedItemsControl* pHeaderedItemsControl, Object* pItems, Object* pHeader) : ModelTreeEnumerator(pHeader), m_pOwner(pHeaderedItemsControl), m_pItems(pItems) { }

protected:
    virtual bool MoveNext() AVUI_OVERRIDE;
    virtual void Reset() AVUI_OVERRIDE;

    virtual TRefCountedPtr<Object> get_Current() AVUI_OVERRIDE;
    virtual bool get_IsUnchanged() AVUI_OVERRIDE;

private:
    TRefCountedPtr<Object> m_pItems;
    TWeakPtr<HeaderedItemsControl> m_pOwner;
};

class PopupModelTreeEnumerator : public ModelTreeEnumerator
{
public:
    DECLARE_ELEMENT(PopupModelTreeEnumerator, ModelTreeEnumerator);
    PopupModelTreeEnumerator(Popup* pPopup, Object* pChild) : ModelTreeEnumerator(pChild), m_pPopup(pPopup) { }

protected:
    virtual bool get_IsUnchanged() AVUI_OVERRIDE;

private:
    TWeakPtr<Popup> m_pPopup;
};

class SingleChildEnumerator : public Object, public IEnumerator
{
public:

#pragma region Internal Methods

    DECLARE_ELEMENT(SingleChildEnumerator, Object);
    SingleChildEnumerator(Object* pChild) : m_index(-1), m_pChild(pChild), m_count(pChild == NULL ? 0 : 1) { }

#pragma endregion Internal Methods

protected:

#pragma region Protected Methods

    virtual bool MoveNext() { m_index++; return m_index < m_count; }
    virtual void Reset() { m_index = -1; }
    bool IsInvalid() AVUI_OVERRIDE { return false; }

#pragma endregion Protected Methods

#pragma region Protected Properties

    virtual TRefCountedPtr<Object> get_Current() { if(m_index != 0) return NULL; return m_pChild; }
    Object* get_Object() { return this; }

#pragma endregion Protected Properties

private:

#pragma region Private Fields

    TRefCountedPtr<Object> m_pChild;
    int m_count;
    int m_index;

#pragma endregion Private Fields

};

}; // namespace AVUI

